package com.xt.base.reflection;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

public class IClass implements Iterable<IClass.Field>{
	
	public final Object target;
	private final java.lang.reflect.Field[] fields;
	private static Method FiledMethod = null;
	
	/***
	 *@param o::Object  被迭代的对象
	 ****/
	public IClass(Object o){
		this.target = o;
		this.fields = BaseReflector.getAllField(o.getClass());
	}

	/***
	 *@param o::Object  被迭代的对象
	 *@param es::EspecialProperties,需过滤掉的属性
	 ****/
	public IClass(Object o,EspecialProperties es){
		this(o,es == null?null:es.getProperties().toArray(new String[0]),true);
	}

	/***
	 *@param o::Object  被迭代的对象
	 *@param names::String[],仅包含的属性
	 ****/
	public IClass(Object o,String[] names){
		this(o,names,false);
	}

	/***
	 *@param o::Object  被迭代的对象
	 *@param names::String[],属性集合，仅包含或需过滤由uninclude指定
	 *@param uninclude::boolean,true 过滤，false 仅包含
	 ****/
	public IClass(Object o,String[] names,boolean uninclude){
		this.target = o;
		if(!uninclude){			
			this.fields = names == null?new java.lang.reflect.Field[0]:
					Apply.each(names, getFiledMethod(),BaseReflector.class, 
							new java.lang.reflect.Field[names.length],1,o.getClass());
		}else this.fields = BaseReflector.getAllField(o.getClass(),names);	 
	}

	/***
	 *@param o::Object  被迭代的对象
	 *@param names::Iterator<String>,仅包含的属性
	 ****/
	public IClass(Object o,Iterator<String> names){
		this.target = o;
		if(names != null){
			Class c = o.getClass();
			Set<java.lang.reflect.Field> f = new HashSet<java.lang.reflect.Field>();
			while(names.hasNext()){
				String name = names.next();
				java.lang.reflect.Field fid = BaseReflector.getFieldFromAssign(c, name);
				if(fid != null)f.add(fid);
				else log.error("Error field name:" + name + " of " + target.getClass());
			}
			this.fields = f.toArray(new java.lang.reflect.Field[f.size()]);
		}else this.fields = new java.lang.reflect.Field[0];
	}

	public Iterator<Field> iterator() {
		return new Iterator<Field>(){
			private int index = 0;
			public boolean hasNext() {
				return index < fields.length;
			}
			public Field next() {
				return new Field(fields[index++]);
			}
			public void remove() {
				throw new UnsupportedOperationException();
			}
		};
	}
	
	public interface FieldWraper<T>{
		abstract public T wrapField(Field f)throws Exception;
	}
	
	final public class Field{
		public final java.lang.reflect.Field field;
		private Boolean c = null;
		private Object v = null;
		private boolean geted = false;
		
		public Field(java.lang.reflect.Field field){
			this.field = field;
		}
		
		@SuppressWarnings("unchecked")
		final public<T> T value(){
			if(!geted){
				v = value(target);
				geted = true;
			}
			return (T)v;
		}
		
		final public<T> T value(FieldWraper<T> wraper){
			try{
				return wraper.wrapField(this);
			}catch(Exception e){
				throw new RuntimeException(e);
			}
		}
		
		@SuppressWarnings("unchecked")
		final public<T> T value(Object anObject){
			try{
				if(field != null)
					return (T)BaseReflector.getValueIgnoreAccessable(anObject, field);
				 throw new RuntimeException("Empty Field error.");
			}catch(Exception e){
				log.error(anObject.getClass() + "." + name() + " get error",e);
				throw new RuntimeException(e);
			}
		}
		
		final public boolean isCollection(){
			if(field == null)return false;
			if(c == null)
				c = BaseReflector.isCollection(field.getType());
			return c;
		}
		
		final public String name(){
			return field == null?null:field.getName();
		}
		
		final public Class type(){
			return field == null?null:field.getType();
		}
		
		final public Object target(){
			return target;
		}
		
		final public void set(Object value){
			set(target,value);
		}
		
		final public void set(Object anObject,Object value){
			try{
				BaseReflector.setValueIgnoreAccessable(anObject, field, value);
			}catch(Exception e){
				throw new RuntimeException(e);
			}
		}
		
		final public boolean isSimpleType(){
			return field == null?false:BaseReflector.isSimpleType(field.getType());
		}
		
		final public boolean isArray(){
			return field == null?false:field.getType().isArray();
		}
		
		final public boolean isTransient(){
			return (field.getModifiers() & Modifier.TRANSIENT) == Modifier.TRANSIENT;
		}
		
		final public boolean isStatic(){
			return (field.getModifiers() & Modifier.STATIC) == Modifier.STATIC;
		}
		
		final public boolean isStaticOrTransient(){
			int mark = Modifier.STATIC | Modifier.TRANSIENT;
			return (field.getModifiers() & mark) == mark;
		}
		
		final public boolean is(Class<?> clazz){
			if(clazz == null)return false;
			if(clazz == field.getType())return true;
			return clazz.isAssignableFrom(field.getType()) || field.getType().isAssignableFrom(clazz);
		}
		
		final public boolean isThis(){
			try{
				return value() == target;
			}catch(Exception e){
				return false;
			}
		}
	}
	
	private static Method getFiledMethod(){
		try{
			if(FiledMethod == null)
				FiledMethod = BaseReflector.class.getMethod("getFieldFromAssign", new Class[]{Class.class,String.class});
			return FiledMethod;
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
	
	private static final org.apache.log4j.Logger 
		log = org.apache.log4j.Logger.getLogger(IClass.class);
}
